#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fs.h>


int major;
struct class *hc_key_class;

struct gpio_irq {
	int gpio;
	int irq;
};

static struct gpio_irq *gp_irq;

static irqreturn_t key_irq_handler(int irq, void *dev)
{
	struct gpio_irq *girq = dev;

	printk("key_irq happend, irq = %d, gpio = %d\n", girq->irq, girq->gpio);
	return IRQ_HANDLED;	
}

/*=============================platform_driver==============================*/
/* 匹配内核根据设备树生成的platform_device */
static int my_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	int gpio_cnt,i,err;
	
	/* 获得GPIO个数 */
	gpio_cnt = of_gpio_count(node);

	/* 向内核申请空间，存储gpio号和irq */
	gp_irq = kzalloc(gpio_cnt * sizeof(struct gpio_irq), GFP_KERNEL);

	for(i = 0; i < gpio_cnt; i++){
		//获取GPIO
		gp_irq[i].gpio = of_get_gpio(node, i);
		
		//GPIO转换成中断号
		gp_irq[i].irq = gpio_to_irq(gp_irq[i].gpio);
	
		//中断请求
		err = request_irq(gp_irq[i].irq, key_irq_handler, IRQF_TRIGGER_FALLING, "hc_key_irq", &gp_irq[i]);
	}

	printk("my_probe run\n");
	
	return 0;
}

static int my_remove(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	int gpio_cnt,i;
	
	/* 获得GPIO个数 */
	gpio_cnt = of_gpio_count(node);

	for(i = 0; i < gpio_cnt; i++){
		free_irq(gp_irq[i].irq, &gp_irq[i]);
	}

	printk("my_remove run\n");

	return 0;
}

static struct of_device_id hc_key_match[] = {
	{.compatible = "hc-key"}, 
	{},
};

static struct platform_driver dev_driver = {
	.probe		=	my_probe,	
	.remove		= 	my_remove,
	.driver		= {
		.name	= "my_platform_driver",
		.of_match_table = hc_key_match,
	},
};

/*=============================驱动出入口函数==============================*/
/* 驱动入口函数：insmod xx.ko 时会被调用 */
static int dev_init(void)
{	
	platform_driver_register(&dev_driver);

	return 0;
}

/* 驱动出口函数： rmmod xx.ko 时会被调用 */
static void dev_exit(void)
{
	platform_driver_unregister(&dev_driver);
	printk("hc_key driver exit\n");
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
